{*******************************************************************************
* The contents of this file are used with permission, subject to the Mozilla   *
* Public License Version 1.1 (the "License"); you may not use this file except *
* in compliance with the License. You may obtain a copy of the License at      *
* http://www.mozilla.org/MPL/                                                  *
*                                                                              *
* Software distributed under the License is distributed on an "AS IS" basis,   *
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for *
* the specific language governing rights and limitations under the License.    *
*                                                                              *
* The Original Code is distributed as part of the "mediate" product and is     *
* Copyright (C) @home media limited. All Rights Reserved.                      *
*                                                                              *
* Email: support@athomemedia.co.uk                                             *
* Web:   http://www.athomemedia.co.uk                                          *
*******************************************************************************}

unit Gauges;

interface

uses
 Classes, UIObjects, Colours, Bitmaps, XMLHelper;

{$IFDEF DESIGNER}
const
  // Property categories and hints for designer
  CAT_DESIGN = 'Design';
  CAT_POINTER = 'Pointer';

  HINT_ALIGN = 'specifies optional position alignment for the pointer';
  HINT_POINTERWIDTH = 'specifies width/thickness of the pointer';
  HINT_POINTERLENGTH = 'specifies length of the pointer';
  HINT_POINTERX = 'specifies the pointer horizontal position within the gauge';
  HINT_POINTERY = 'specifies the pointer vertical position within the gauge';
  HINT_ROTATEX = 'specifies the horizontal axis of rotation for the pointer';
  HINT_ROTATEY = 'specifies the vertical axis of rotation for the pointer';
  HINT_POINTERIMAGE = 'specifies the name of a bitmap item to use for drawing the pointer';
  HINT_COLOUR = 'specifies the name of a colour item to use for drawing the pointer';
  HINT_STARTANGLE = 'specifies the start angle in degrees for the pointer movement';
  HINT_SWEEPANGLE = 'specifies the sweep angle in degrees for the pointer movement';
  HINT_BACKGROUND = 'specifies the name of a bitmap item to use for drawing the background';
  HINT_WIDTH = 'specifies width for the Gauge';
  HINT_HEIGHT = 'specifies height for the Gauge';
{$ENDIF}

type
  TAHMPointerAlign = (paNone, paCenter, paTopLeft, paTop, paTopRight, paRight,
                      paBottomRight, paBottom, paBottomLeft, paLeft);

  TAHMGauge = class(TAHMUIDisplayObject)
  private
    FAligning: Boolean;
    FPointerAlign: TAHMPointerAlign;
    FPointerLength: Single;
    FPointerWidth: Single;
    FPointerCenterX: Single;
    FPointerCenterY: Single;
    FRotateCenterX: Single;
    FRotateCenterY: Single;
    FStartAngle: Integer;
    FSweepAngle: Integer;
    FVirtPointerLength: Integer;
    FVirtPointerWidth: Integer;
    FVirtPointerCenterX: Integer;
    FVirtPointerCenterY: Integer;
    FVirtRotateCenterX: Integer;
    FVirtRotateCenterY: Integer;
    FBackground: TAHMBitmap;
    FPointerImage: TAHMBitmap;
    FPointerColour: TAHMColour;
  protected
    function Align2Str(Value: TAHMPointerAlign): String;
    function Str2Align(Value: String): TAHMPointerAlign;
    procedure SetPointerAlign(Align: TAHMPointerAlign);
    procedure SetVirtualPointerLength(Length: Integer);
    procedure SetVirtualPointerWidth(Width: Integer);
    procedure SetVirtualPointerCenterX(X: Integer);
    procedure SetVirtualPointerCenterY(Y: Integer);
    procedure SetVirtualRotateCenterX(X: Integer);
    procedure SetVirtualRotateCenterY(Y: Integer);
    procedure SetVirtualWidth(Width: Integer); override;
    procedure SetVirtualHeight(Height: Integer); override;
    procedure SetStartAngle(StartAngle: Integer);
    procedure SetSweepAngle(SweepAngle: Integer);
    procedure AlignPointer;
    procedure ClearProperties; override;
  public
    constructor Create(const Name: String); override;
    property PointerLength: Single read FPointerLength write FPointerLength;
    property PointerWidth: Single read FPointerWidth write FPointerWidth;
    property PointerCenterX: Single read FPointerCenterX write FPointerCenterX;
    property PointerCenterY: Single read FPointerCenterY write FPointerCenterY;
    property RotateCenterX: Single read FRotateCenterX write FRotateCenterX;
    property RotateCenterY: Single read FRotateCenterY write FRotateCenterY;
    procedure ConfigurePreview(Control: TObject); override;
    procedure Render(Control: TObject; iX, iY, iWidth, iHeight: Single); override;
    procedure SeedObject; override;
    procedure Assign(Source: TPersistent); override;
    procedure SaveXMLBody(Lines: TStrings); override;
    procedure ParseFromXML(XML: TAHMXMLHelper); override;
    procedure BuildProperties(Properties: TAHMUIPropertyList); override;
  published
    property PointerAlign: TAHMPointerAlign read FPointerAlign write SetPointerAlign;
    property VirtualPointerLength: Integer read FVirtPointerLength write SetVirtualPointerLength;
    property VirtualPointerWidth: Integer read FVirtPointerWidth write SetVirtualPointerWidth;
    property VirtualPointerCenterX: Integer read FVirtPointerCenterX write SetVirtualPointerCenterX;
    property VirtualPointerCenterY: Integer read FVirtPointerCenterY write SetVirtualPointerCenterY;
    property VirtualRotateCenterX: Integer read FVirtRotateCenterX write SetVirtualRotateCenterX;
    property VirtualRotateCenterY: Integer read FVirtRotateCenterY write SetVirtualRotateCenterY;
    property StartAngle: Integer read FStartAngle write SetStartAngle;
    property SweepAngle: Integer read FSweepAngle write SetSweepAngle;
    property Background: TAHMBitmap read FBackground write FBackground;
    property PointerImage: TAHMBitmap read FPointerImage write FPointerImage;
    property PointerColour: TAHMColour read FPointerColour write FPointerColour;
    // Publish inherited properties
    property VirtualWidth;
    property VirtualHeight;
  end;

  TAHMGaugeList = class(TAHMUIObjectList)
  private
  protected
  public
    constructor Create; override;
    function AddGauge(const InheritFrom, NewName: String): TAHMGauge;
    function GetGauge(const Name: String): TAHMGauge;
    procedure PopulateDefaultObjects; override;
    procedure CleardownDefaultObjects; override;
  end;

implementation

uses SysUtils, ApplicationManager, Screen, Colour, BaseControls, UIControls,
     MetaConsts, TagNames, XMLTags, ErrorCodes, AHMTypes;

// TAHMGaugeList

constructor TAHMGaugeList.Create;
begin
  inherited Create;

  XMLTagName := TAG_GAUGES;
  ChildClass := TAHMGauge;
end;

function TAHMGaugeList.AddGauge(const InheritFrom, NewName: String): TAHMGauge;
begin
  Result := TAHMGauge(Inherit(InheritFrom, NewName));
end;

function TAHMGaugeList.GetGauge(const Name: String): TAHMGauge;
begin
  Result := TAHMGauge(GetObject(Name));
end;

procedure TAHMGaugeList.PopulateDefaultObjects;
begin
  with ApplicationManagerInstance.ThemeManager, DefaultObject as TAHMGauge do
  begin
    PointerAlign := paCenter;
    VirtualWidth := 200;
    VirtualHeight := 200;
    VirtualPointerLength := 60;
    VirtualPointerWidth := 5;
    StartAngle := 150;
    SweepAngle := 260;
    PointerColour := TAHMColour.Create('Red');
    PointerColour.ColourDef := 'd0ff0000';
    Background := TAHMBitmap(ThemeObjects[otBitmaps].DefaultObjects[TAG_GAUGE]);
  end;
end;

procedure TAHMGaugeList.CleardownDefaultObjects;
begin
  with DefaultObject as TAHMGauge do
    PointerColour.Free;
end;

//----------------------------------------------------------------------------//

// TAHMGauge

constructor TAHMGauge.Create(const Name: String);
begin
  inherited Create(Name);

  XMLTagName := TAG_GAUGE;
  ObjectType := otGauges;
  ImageIndex := Ord(otGauges);

{$IFDEF DESIGNER}
  // Render preview using a gauge control
  PreviewControlClass := TAHMGaugeControl;
{$ENDIF}

  ClearProperties;
end;

function TAHMGauge.Align2Str(Value: TAHMPointerAlign): String;
begin
  if Value = paCenter then Result := ATTR_VAL_CENTER
  else if Value = paTopLeft then Result := ATTR_VAL_TOPLEFT
  else if Value = paTop then Result := ATTR_VAL_TOP
  else if Value = paTopRight then Result := ATTR_VAL_TOPRIGHT
  else if Value = paRight then Result := ATTR_VAL_RIGHT
  else if Value = paBottomRight then Result := ATTR_VAL_BOTTOMRIGHT
  else if Value = paBottom then Result := ATTR_VAL_BOTTOM
  else if Value = paBottomLeft then Result := ATTR_VAL_BOTTOMLEFT
  else if Value = paLeft then Result := ATTR_VAL_LEFT
  else Result := '';
end;

function TAHMGauge.Str2Align(Value: String): TAHMPointerAlign;
begin
  if Value = ATTR_VAL_CENTER then Result := paCenter
  else if Value = ATTR_VAL_TOPLEFT then Result := paTopLeft
  else if Value = ATTR_VAL_TOP then Result := paTop
  else if Value = ATTR_VAL_TOPRIGHT then Result := paTopRight
  else if Value = ATTR_VAL_RIGHT then Result := paRight
  else if Value = ATTR_VAL_BOTTOMRIGHT then Result := paBottomRight
  else if Value = ATTR_VAL_BOTTOM then Result := paBottom
  else if Value = ATTR_VAL_BOTTOMLEFT then Result := paBottomLeft
  else if Value = ATTR_VAL_LEFT then Result := paLeft
  else Result := paNone;
end;

procedure TAHMGauge.SetPointerAlign(Align: TAHMPointerAlign);
begin
  FPointerAlign := Align;
  AlignPointer;
end;

procedure TAHMGauge.SetVirtualPointerLength(Length: Integer);
begin
  FVirtPointerLength := Length;
  FPointerLength := ScreenInstance.ScaleVirtualY(Length);
end;

procedure TAHMGauge.SetVirtualPointerWidth(Width: Integer);
begin
  FVirtPointerWidth := Width;
  FPointerWidth := ScreenInstance.ScaleVirtualX(Width);
end;

procedure TAHMGauge.SetVirtualPointerCenterX(X: Integer);
begin
  FVirtPointerCenterX := X;
  FPointerCenterX := ScreenInstance.ScaleVirtualX(X);
  if not FAligning then FPointerAlign := paNone;
end;

procedure TAHMGauge.SetVirtualPointerCenterY(Y: Integer);
begin
  FVirtPointerCenterY := Y;
  FPointerCenterY := ScreenInstance.ScaleVirtualY(Y);
  if not FAligning then FPointerAlign := paNone;
end;

procedure TAHMGauge.SetVirtualRotateCenterX(X: Integer);
begin
  FVirtRotateCenterX := X;
  FRotateCenterX := ScreenInstance.ScaleVirtualX(X);
end;

procedure TAHMGauge.SetVirtualRotateCenterY(Y: Integer);
begin
  FVirtRotateCenterY := Y;
  FRotateCenterY := ScreenInstance.ScaleVirtualY(Y);
end;

procedure TAHMGauge.SetVirtualWidth(Width: Integer);
begin
  inherited;
  AlignPointer;
end;

procedure TAHMGauge.SetVirtualHeight(Height: Integer);
begin
  inherited;
  AlignPointer;
end;

procedure TAHMGauge.SetStartAngle(StartAngle: Integer);
begin
  FStartAngle := Abs(StartAngle) mod 360;
end;

procedure TAHMGauge.SetSweepAngle(SweepAngle: Integer);
begin
  FSweepAngle := SweepAngle mod 360;
end;

procedure TAHMGauge.AlignPointer;
begin
  // Avoid recursive alignment calls
  if FAligning then Exit else FAligning := True;
  try
    // Auto align pointer
    case FPointerAlign of
      paCenter: begin
        VirtualPointerCenterX := VirtualWidth div 2;
        VirtualPointerCenterY := VirtualHeight div 2;
      end;
      paTopLeft: begin
        VirtualPointerCenterX := 0;
        VirtualPointerCenterY := 0;
      end;
      paTop: begin
        VirtualPointerCenterX := VirtualWidth div 2;
        VirtualPointerCenterY := 0;
      end;
      paTopRight: begin
        VirtualPointerCenterX := VirtualWidth;
        VirtualPointerCenterY := 0;
      end;
      paRight: begin
        VirtualPointerCenterX := VirtualWidth;
        VirtualPointerCenterY := VirtualHeight div 2;
      end;
      paBottomRight: begin
        VirtualPointerCenterX := VirtualWidth;
        VirtualPointerCenterY := VirtualHeight;
      end;
      paBottom: begin
        VirtualPointerCenterX := VirtualWidth div 2;
        VirtualPointerCenterY := VirtualHeight;
      end;
      paBottomLeft: begin
        VirtualPointerCenterX := 0;
        VirtualPointerCenterY := VirtualHeight;
      end;
      paLeft: begin
        VirtualPointerCenterX := 0;
        VirtualPointerCenterY := VirtualHeight div 2;
      end;
    end;
  finally
    FAligning := False;
  end;
end;

procedure TAHMGauge.ClearProperties;
begin
  inherited;

  // Clear custom Gauge properties
  VirtualPointerLength := 0;
  VirtualPointerWidth := 0;
  VirtualPointerCenterX := 0;
  VirtualPointerCenterY := 0;
  VirtualRotateCenterX := 0;
  VirtualRotateCenterY := 0;
  FPointerAlign := paCenter;
  FStartAngle := 0;
  FSweepAngle := 0;
  FBackground := nil;
  FPointerImage := nil;
  FPointerColour := nil;
end;

procedure TAHMGauge.ConfigurePreview(Control: TObject);
begin
{$IFDEF DESIGNER}
  with Control as TAHMGaugeControl do
  begin
    // Setup metadata for Gauge
    MetaValue := META_PREVIEW_GAUGE_VALUE;
    MetaGroup := META_PREVIEW_GAUGE_MAX;

    // MetaIndex is used to store the movement direction
    if (MetaIndex = '') or (Position = 0) then MetaIndex := 'up'
    else if Position = Maximum then MetaIndex := 'down';

    // Increment metadata value to animate Gauge control for preview
    with ApplicationManagerInstance do
      if MetaIndex = 'up' then MetaDataManager.IncMeta(MetaValue, MetaGroup)
                          else MetaDataManager.DecMeta(MetaValue, MetaGroup);
  end;
{$ENDIF}
end;

procedure TAHMGauge.Render(Control: TObject; iX, iY, iWidth, iHeight: Single);
var
  GaugePos, GaugeMax: Integer;
  Angle: Single;
begin
  // Pre-render our control if necessary
  inherited;

  with Control as TAHMGaugeControl do
  begin
    // Get gauge position and maximum properties
    GaugePos := Position;
    GaugeMax := Maximum;

    // Calculate angle for pointer
    if GaugeMax <> 0 then
      Angle := FStartAngle + (GaugePos / GaugeMax * FSweepAngle)
    else
      Angle := FStartAngle;

    // Render gauge background
    if Assigned(FBackground) then
      FBackground.Render(Control, iX, iY, iWidth, iHeight);

    with Viewport.Canvas do
    begin
      // Calculate 3D rotation origin for pointer sprite rendering,
      // or just 2D rotation angle for line rendering
      // sprite rendering, or to whole screen for line rendering
      if Assigned(FPointerImage) then
      begin
        Set3DRotateOrigin(FRotateCenterX, FRotateCenterY, FPointerLength, FPointerWidth);
        Set3DRotation(0.0, 0.0, Angle);
      end
      else
        SetRotation(0.0, 0.0, Angle, iX + FPointerCenterX, iY + FPointerCenterY);

      // Render pointer - use of bitmap is preferred over line
      if Assigned(FPointerImage) then
      begin
        // Calculate absolute pointer position
        iX := iX + FPointerCenterX;
        iY := iY + FPointerCenterY;

        FPointerImage.Render(Control, iX, iY, FPointerLength, FPointerWidth);
      end
      else
      begin
        // Calculate absolute pointer position - offset for pointer origin
        iX := iX + FPointerCenterX - FRotateCenterX;
        iY := iY + FPointerCenterY - FRotateCenterY;

        PenWidth := FPointerWidth;
        PenColour := TAHMCanvasColour.White;
        MoveTo(iX, iY);

        // Use pointer colour for gamma correction if assigned
        if Assigned(FPointerColour) then
          Viewport.Canvas.LineTo(iX + FPointerLength, iY, FPointerColour.Colour)
        else
          Viewport.Canvas.LineTo(iX + FPointerLength, iY, nil);
      end;

      // Revert back to 2D rendering mode
      if Assigned(FPointerImage) then UnSet3DRotation
                                 else UnSetRotation;
    end;
  end;
end;

procedure TAHMGauge.SeedObject;
begin
{$IFDEF DESIGNER}
  if Ancestor = nil then
    with ApplicationManagerInstance.ThemeManager.VisualDescriptor do
    begin
      PointerAlign := paCenter;
      VirtualWidth := 200;
      VirtualHeight := 200;
      VirtualPointerLength := 60;
      VirtualPointerWidth := 5;
      StartAngle := 150;
      SweepAngle := 260;
      PointerColour := ColourList.GetColour(DEFAULT_WHITE_NAME);
    end;
{$ENDIF}
end;

procedure TAHMGauge.Assign(Source: TPersistent);
begin
  inherited Assign(Source);

  with Source as TAHMGauge do
  begin
    Self.VirtualPointerLength := VirtualPointerLength;
    Self.VirtualPointerWidth := VirtualPointerWidth;
    Self.VirtualPointerCenterX := VirtualPointerCenterX;
    Self.VirtualPointerCenterY := VirtualPointerCenterY;
    Self.VirtualRotateCenterX := VirtualRotateCenterX;
    Self.VirtualRotateCenterY := VirtualRotateCenterY;
    Self.PointerAlign := PointerAlign;
    Self.StartAngle := StartAngle;
    Self.SweepAngle := SweepAngle;
    Self.Background := Background;
    Self.PointerImage := PointerImage;
    Self.PointerColour := PointerColour;
  end;
end;

procedure TAHMGauge.SaveXMLBody(Lines: TStrings);
var
  oAncs: TAHMGauge;
  sWork: String;
begin
  // Determine which ancestor to compare against - real or empty
  oAncs := TAHMGauge(ObjectToCompare);

  // Store pointer properties
  Lines.Add(TABS[3] + TGB+TAG_POINTER+TGC);

  // Do we need to store alignment?
  if (FPointerAlign <> paCenter) and (FPointerAlign <> oAncs.PointerAlign) then
    Lines.Add(TABS[4] + TGB+TAG_ALIGNMENT+TGC + Align2Str(FPointerAlign) + TGE+TAG_ALIGNMENT+TGC);

  // Do we need to store pointer length?
  if (FVirtPointerLength <> 0) and (FVirtPointerLength <> oAncs.VirtualPointerLength) then
    Lines.Add(TABS[4] +TGB+TAG_LENGTH+TGC+ IntToStr(FVirtPointerLength) + TGE+TAG_LENGTH+TGC);

  // Do we need to store pointer width?
  if (FVirtPointerWidth <> 0) and (FVirtPointerWidth <> oAncs.VirtualPointerWidth) then
    Lines.Add(TABS[4] +TGB+TAG_WIDTH+TGC+ IntToStr(FVirtPointerWidth) + TGE+TAG_WIDTH+TGC);

  // Do we need to store pointer position?
  if ((FVirtPointerCenterX <> 0) and (FVirtPointerCenterX <> oAncs.VirtualPointerCenterX)) or
     ((FVirtPointerCenterY <> 0) and (FVirtPointerCenterY <> oAncs.VirtualPointerCenterY)) then
    Lines.Add(TABS[4] + TGB+TAG_CENTER+TGC + IntToStr(FVirtPointerCenterX) + ',' +
              IntToStr(FVirtPointerCenterY) + TGE+TAG_CENTER+TGC);

  // Do we need to store pointer rotation axis?
  if ((FVirtRotateCenterX <> 0) and (FVirtRotateCenterX <> oAncs.VirtualRotateCenterX)) or
     ((FVirtRotateCenterY <> 0) and (FVirtRotateCenterY <> oAncs.VirtualRotateCenterY)) then
    Lines.Add(TABS[4] + TGB+TAG_ROTATE+TGC + IntToStr(FVirtRotateCenterX) + ',' +
              IntToStr(FVirtRotateCenterY) + TGE+TAG_ROTATE+TGC);

  // Do we need to store pointer bitmap?
  if (FPointerImage <> nil) and (FPointerImage <> oAncs.PointerImage) then
    Lines.Add(TABS[4] + FPointerImage.XMLReference);

  // Do we need to store pointer colour?
  if (FPointerColour <> nil) and (FPointerColour <> oAncs.PointerColour) then
    Lines.Add(TABS[4] + FPointerColour.XMLReference);

  Lines.Add(TABS[3] + EndTag(TAG_POINTER));

  // Do we need to store background bitmap?
  if (FBackground <> nil) and (FBackground <> oAncs.Background) then
    Lines.Add(TABS[3] + FBackground.XMLReference(TAG_BACKGROUND));

  // Do we need to store start and sweep angle?
  if ((FStartAngle <> 0) and (FStartAngle <> oAncs.StartAngle)) or
     ((FSweepAngle <> 0) and (FSweepAngle <> oAncs.SweepAngle)) then
  begin
    sWork := TGB+TAG_GEOMETRY;
    if (FStartAngle <> 0) and (FStartAngle <> oAncs.StartAngle) then
      sWork := sWork + SPC+ATTR_ANGLE+ATB + IntToStr(FStartAngle) + ATQ;
    if (FSweepAngle <> 0) and (FSweepAngle <> oAncs.SweepAngle) then
      sWork := sWork + SPC+ATTR_SWEEP+ATB + IntToStr(FSweepAngle) + ATQ;
    Lines.Add(TABS[3] + sWork + ETE);
  end;

  // Do we need to store size?
  if ((VirtualWidth <> 0) and (VirtualWidth <> oAncs.VirtualWidth)) or
     ((VirtualHeight <> 0) and (VirtualHeight <> oAncs.VirtualHeight)) then
    Lines.Add(TABS[3] + TGB+TAG_SIZE+TGC+ IntToStr(VirtualWidth) + ',' +
              IntToStr(VirtualHeight) + TGE+TAG_SIZE+TGC);
end;

procedure TAHMGauge.ParseFromXML(XML: TAHMXMLHelper);
var
  sAlign, sValue, sName, sStart, sSweep: String;
  iX, iY: Integer;
  GaugeNode, PropsNode, DetailNode: TAHMXMLNode;
begin
  // Initialise parsing nodes
  GaugeNode := XML.CurrentNode;
  PropsNode := nil;

  // All Gauge elements are optional, so see what we have
  while XML.NextElement(GaugeNode, PropsNode) do
    with ApplicationManagerInstance.ThemeManager.VisualDescriptor do
    begin
      if XML.CurrentElement = TAG_POINTER then
      begin
        // Handle Gauge pointer properties
        DetailNode := nil;
        while XML.NextElement(PropsNode, DetailNode) do
        begin
          if XML.CurrentElement = TAG_ALIGNMENT then
          begin
            sAlign := XML.GetValue;
            if sAlign <> '' then PointerAlign := Str2Align(sAlign);
          end
          else if XML.CurrentElement = TAG_LENGTH then
          begin
            sValue := XML.GetValue;
            if sValue <> '' then VirtualPointerLength := StrToIntDef(sValue, 0);
          end
          else if XML.CurrentElement = TAG_WIDTH then
          begin
            sValue := XML.GetValue;
            if sValue <> '' then VirtualPointerWidth := StrToIntDef(sValue, 0);
          end
          else if XML.CurrentElement = TAG_CENTER then
          begin
            if XML.GetCoordsValue(iX, iY) then
            begin
              VirtualPointerCenterX := iX;
              VirtualPointerCenterY := iY;
            end
            else
              LogParsingError(THM_PRS_VIS_MALFORMED_GAUGE_CENTER_TAGS, Self);
          end
          else if XML.CurrentElement = TAG_ROTATE then
          begin
            if XML.GetCoordsValue(iX, iY) then
            begin
              VirtualRotateCenterX := iX;
              VirtualRotateCenterY := iY;
            end
            else
              LogParsingError(THM_PRS_VIS_MALFORMED_GAUGE_ROTATE_TAGS, Self);
          end
          else if XML.CurrentElement = TAG_BITMAP then
          begin
            sName := XML.GetAttribute(ATTR_NAME);
            PointerImage := BitmapList.GetBitmap(sName);
          end
          else if XML.CurrentElement = TAG_COLOUR then
          begin
            sName := XML.GetAttribute(ATTR_NAME);
            PointerColour := ColourList.GetColour(sName);
          end
          else
            LogParsingError(THM_PRS_VIS_UNSUPPORTED_GAUGE_PTR_PROP, Self);
        end;
      end
      else if XML.CurrentElement = TAG_BACKGROUND then
      begin
        sName := XML.GetAttribute(ATTR_NAME);
        Background := BitmapList.GetBitmap(sName);
      end
      else if XML.CurrentElement = TAG_GEOMETRY then
      begin
        sStart := XML.GetAttribute(ATTR_ANGLE);
        sSweep := XML.GetAttribute(ATTR_SWEEP);
        if sStart <> '' then StartAngle := StrToIntDef(sStart, 0);
        if sSweep <> '' then SweepAngle := StrToIntDef(sSweep, 0);
      end
      else if XML.CurrentElement = TAG_SIZE then
      begin
        if XML.GetCoordsValue(iX, iY) then
        begin
          VirtualWidth := iX;
          VirtualHeight := iY;
        end
        else
          LogParsingError(THM_PRS_VIS_MALFORMED_GAUGE_SIZE_TAGS, Self);
      end;
    end;
end;

procedure TAHMGauge.BuildProperties(Properties: TAHMUIPropertyList);
begin
{$IFDEF DESIGNER}
  inherited;

  // Build custom gauge properties
  Properties.Add('Alignment', 'PointerAlign', CAT_POINTER, HINT_ALIGN);
  Properties.Add('Length', 'VirtualPointerLength', CAT_POINTER, HINT_POINTERLENGTH);
  Properties.Add('Width', 'VirtualPointerWidth', CAT_POINTER, HINT_POINTERWIDTH);
  Properties.Add('Center X', 'VirtualPointerCenterX', CAT_POINTER, HINT_POINTERX);
  Properties.Add('Center Y', 'VirtualPointerCenterY', CAT_POINTER, HINT_POINTERY);
  Properties.Add('Rotation X', 'VirtualRotateCenterX', CAT_POINTER, HINT_ROTATEX);
  Properties.Add('Rotation Y', 'VirtualRotateCenterY', CAT_POINTER, HINT_ROTATEY);
  Properties.Add('Image', 'PointerImage', CAT_POINTER, HINT_POINTERIMAGE);
  Properties.Add('Colour', 'PointerColour', CAT_POINTER, HINT_COLOUR);
  Properties.Add('Start Angle', 'StartAngle', CAT_DESIGN, HINT_STARTANGLE);
  Properties.Add('Sweep Angle', 'SweepAngle', CAT_DESIGN, HINT_SWEEPANGLE);
  Properties.Add('Background', 'Background', CAT_DESIGN, HINT_BACKGROUND);
  Properties.Add('Width', 'VirtualWidth', CAT_DESIGN, HINT_WIDTH);
  Properties.Add('Height', 'VirtualHeight', CAT_DESIGN, HINT_HEIGHT);
{$ENDIF}
end;


end.
